#include <iostream>
#include <sstream>
#include "GameIO.h"
#include "Manager.h"
#include "Timer.h"
#include "Scene.h"
#include "Background.h"

GameIO :: GameIO()
{
	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_SWSURFACE);
	if(!screen)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	manager = new Manager(this);
	timer = new Timer();
}

void GameIO :: getInput()
{
	bool quit = false;
	SDL_Event event;

	while(!quit)
	{
		timer->start();

		while(SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT)
				quit = true;
		}

		manager->process();
	}
}

void GameIO :: displayMainGame(Scene* scene)
{
	intXY map = scene->getMap();
	Background** bg = scene->getBackground();
	SDL_Rect* camera = scene->getCamera();
	SDL_Surface** mapImg = scene->getMapImg();
	
	showBackground(bg, camera);
	showMap(map, camera, mapImg);

	SDL_Flip(screen);

	while(timer->getTicks() < 1000 / FPS)
	{
	}
}

void GameIO :: showBackground(Background** bg, SDL_Rect* camera)
{
	SDL_Rect* box;
	for(int i = 0; i < BG_NUM; i++)
	{
		box = bg[i]->getBox();
		if(checkCollision(box, camera))
			applySurface(box->x - camera->x, box->y - camera->y, bg[i]->getBg(), screen);
	}
}

void GameIO :: showMap(intXY map, SDL_Rect* camera, SDL_Surface** mapImg)
{
	SDL_Rect box;
	box.w = SIZEX;
	box.h = SIZEY;

	for(int i = 0; i < SCREEN_HEIGHT / SIZEY; i++)
	{
		for(int j = 0;  j < SCREEN_WIDTH / SIZEX; j++)
		{
			if(map[i][j] != -1)
			{
				box.x = j * SIZEY;
				box.y = i * SIZEX;
				if(checkCollision(&box, camera))
					applySurface(box.x - camera->x, box.y - camera->y, mapImg[map[i][j]], screen);
			}
		}
	}
}

bool GameIO :: checkCollision(SDL_Rect* boxA, SDL_Rect* boxB)
{
	int leftA, leftB;
	int rightA, rightB;
	int topA, topB;
	int bottomA, bottomB;

	leftA = boxA->x;
	rightA = boxA->x + boxA->w;
	topA = boxA->y;
	bottomA = boxA->y + boxA->h;

	leftB = boxB->x;
	rightB = boxB->x + boxB->w;
	topB = boxB->y;
	bottomB = boxB->y + boxB->h;

	if(bottomA <= topB)
		return false;
	if(topA >= bottomB)
		return false;
	if(rightA <= leftB)
		return false;
	if(leftA >= rightB)
		return false;

	return true;
}

void GameIO :: applySurface(int x, int y, SDL_Surface* source, SDL_Surface* dest, SDL_Rect* clip)
{
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;

	SDL_BlitSurface(source, clip, dest, &offset);
}
SDL_Surface* GameIO :: loadImg(string filePath)
{
	SDL_Surface* loadedImg = NULL;
	SDL_Surface* optimizedImg = NULL;

	loadedImg = IMG_Load(filePath.c_str());

	if(!loadedImg)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	optimizedImg = SDL_DisplayFormat(loadedImg);
	SDL_FreeSurface(loadedImg);

	if(!optimizedImg)
	{
		cerr << "[ERROR]: " << SDL_GetError() << endl;
		exit(1);
	}

	return optimizedImg;
}

string GameIO :: conToStr(int n)
{
	stringstream sstream;
	sstream << n;
	return sstream.str();
}